package com.binance.feign.ribbon.policy;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.InterceptorRetryPolicy;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
import org.springframework.http.HttpRequest;
import org.springframework.retry.RetryContext;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Fei.Huang on 2018/9/7.
 */
public class FeignRetryPolicy extends InterceptorRetryPolicy {

    private HttpRequest request;
    private String serviceId;

    public FeignRetryPolicy(HttpRequest request, LoadBalancedRetryPolicy policy, ServiceInstanceChooser serviceInstanceChooser, String serviceName) {
        super(request, policy, serviceInstanceChooser, serviceName);
        this.request = request;
        this.serviceId = serviceName;
    }

    @Override
    public boolean canRetry(RetryContext context) {
        if (context.getRetryCount() == 0) {
            return true;
        }
        return super.canRetry(context);
    }

    @Override
    public RetryContext open(RetryContext parent) {
        LoadBalancedRetryContext context = new LoadBalancedRetryContext(parent, this.request);
        context.setServiceInstance(new FeignRetryPolicyServiceInstance(serviceId, request));
        return context;
    }

    class FeignRetryPolicyServiceInstance implements ServiceInstance {

        private String serviceId;
        private HttpRequest request;
        private Map<String, String> metadata;

        FeignRetryPolicyServiceInstance(String serviceId, HttpRequest request) {
            this.serviceId = serviceId;
            this.request = request;
            this.metadata = new HashMap<>();
        }

        @Override
        public String getServiceId() {
            return serviceId;
        }

        @Override
        public String getHost() {
            return request.getURI().getHost();
        }

        @Override
        public int getPort() {
            return request.getURI().getPort();
        }

        @Override
        public boolean isSecure() {
            return "https".equals(request.getURI().getScheme());
        }

        @Override
        public URI getUri() {
            return request.getURI();
        }

        @Override
        public Map<String, String> getMetadata() {
            return metadata;
        }
    }
}